#include <jni.h>
#include <string>
#include <android/log.h>
#include "rtsp_client_api.h"
#include "my_fifo.h"

#define LOG_TAG    "native-lib"
#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

static bc_fifo_handle g_hdlFifo[16] = {NULL};
int my_write264file(int chn, const char *filename, void* data, int size)
{
    int ret = -1;
    int writesize = 0;
    static FILE  *fp[16] = {NULL};
    if (!filename || !data || size == 0)
    {
        LOGI("input param is NULL\n");
        return -1;
    }

    if (!fp[chn])
    {
        fp[chn] = fopen(filename, "wb+");
        if(!fp[chn])
        {
            LOGI("fp is NULL, %s\n", filename);
            return -2;
        }
    }
    writesize = fwrite(data, 1, size, fp[chn]);
    if (writesize != size)
    {
        LOGI("fwrite err, %s\n", filename);
    }
    ret = writesize;
    return ret;
}

void CB_RtspRecv(int _s32Chn, BL_FRAME_DATA_S* _pstFrameData)
{
    static int s32ICount[16] = {0};
    std::string strFileName = "test_chn";
    strFileName += std::to_string(_s32Chn);
    strFileName += ".h264";
    if(_pstFrameData->m_eFrameType == BL_AVFRM_TYPE_I)
    {
        s32ICount[_s32Chn]++;
    }

    // copy frame data to fifo
    BL_FRAME_DATA_S *pstFrameData = (BL_FRAME_DATA_S*) malloc(sizeof(BL_FRAME_DATA_S) + _pstFrameData->m_s32DataSize);
    pstFrameData->m_eEncodeType = _pstFrameData->m_eEncodeType;
    pstFrameData->m_eFrameType = _pstFrameData->m_eFrameType;
    pstFrameData->m_s32DataSize = _pstFrameData->m_s32DataSize;
    pstFrameData->m_u64Pts = _pstFrameData->m_u64Pts;
    pstFrameData->m_pdata = (char *)pstFrameData + sizeof(BL_FRAME_DATA_S);
    memcpy(pstFrameData->m_pdata, _pstFrameData->m_pdata, _pstFrameData->m_s32DataSize);
    LOGI("recv frame.chn : %d , len : %d, 264_265 : %d, I_P : %d, pts : %lld\n", _s32Chn,
         pstFrameData->m_s32DataSize, pstFrameData->m_eEncodeType, pstFrameData->m_eFrameType, pstFrameData->m_u64Pts);
    fifo_Pushin(g_hdlFifo[_s32Chn], (void *)pstFrameData, sizeof(BL_FRAME_DATA_S) + _pstFrameData->m_s32DataSize, NULL);

    if(s32ICount[_s32Chn] >= 1)
    {
        //my_write264file(_s32Chn, strFileName.c_str(), _pstFrameData->m_pdata, _pstFrameData->m_s32DataSize);
    }
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_rtspclientdemo_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_rtspclientdemo_MainActivity_RtspInit(JNIEnv *env, jobject thiz) {
    // TODO: implement RtspInit()
    int ret = 0;
    RTSP_CLEINT_INIT_INFO_S stRtspInit;
    memset(&stRtspInit, 0, sizeof(stRtspInit));
    stRtspInit.m_pVideoCb = (void *)CB_RtspRecv;
    ret = rtsp_init(stRtspInit);

    for(int i = 0; i <16; i++)
    {
        g_hdlFifo[i] = fifo_Create(FIFO_CYC_AUTO, 100);
    }

    LOGI("rtsp_init. return val : %d \n", ret);
    return 0;
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_rtspclientdemo_MainActivity_RtspDeInit(JNIEnv *env, jobject thiz) {
    // TODO: implement RtspDeInit()

    rtsp_deinit();
    return 0;
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_rtspclientdemo_MainActivity_RtspOpenUrl(JNIEnv *env, jobject thiz, jint _s32_chn, jstring _str_url) {
    // TODO: implement RtspOpenUrl()
    const char *pUrl = env->GetStringUTFChars(_str_url, NULL);
    int ret = 0;
    ret = rtsp_open_url(_s32_chn, pUrl);
    LOGI("rtsp_open_url.url : %s, return val : %d\n", pUrl, ret);
    return 0;
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_rtspclientdemo_MainActivity_RtspCloseUrl(JNIEnv *env, jobject thiz, int _s32_chn) {
    // TODO: implement RtspCloseUrl()

    rtsp_close_url(_s32_chn);
    return 0;
}extern "C"
JNIEXPORT jint JNICALL
Java_com_example_rtspclientdemo_MainActivity_RtspGetFrame(JNIEnv *env, jobject thiz, jint _s32_chn,
                                                          jbyteArray __frame_data,
                                                          jintArray __frame_len,
                                                          jintArray __encode_type,
                                                          jintArray __frame_type) {
    // TODO: implement RtspGetFrame()
    int s32Len = 0;
    BL_FRAME_DATA_S *pstFrameData = (BL_FRAME_DATA_S *)fifo_Pullout(g_hdlFifo[_s32_chn], &s32Len);

    if(pstFrameData){
        jbyte *jFrameData = (jbyte *) pstFrameData->m_pdata;
        env->SetByteArrayRegion(__frame_data, 0, pstFrameData->m_s32DataSize, jFrameData);

        jint *jLen = (jint *) &pstFrameData->m_s32DataSize;
        env->SetIntArrayRegion(__frame_len, 0, 1, jLen);

        jint *jEncodeType = (jint *) &pstFrameData->m_eEncodeType;
        env->SetIntArrayRegion(__encode_type, 0, 1, jEncodeType);

        jint *jFrameType = (jint *) &pstFrameData->m_eFrameType;
        env->SetIntArrayRegion(__frame_type, 0, 1, jFrameType);

        free(pstFrameData);
    }
    else{
        int zero = 0;
        jint *jLen = (jint *) &zero;
        env->SetIntArrayRegion(__frame_len, 0, 1, jLen);

        jint *jEncodeType = (jint *) &zero;
        env->SetIntArrayRegion(__encode_type, 0, 1, jEncodeType);

        jint *jFrameType = (jint *) &zero;
        env->SetIntArrayRegion(__frame_type, 0, 1, jFrameType);
    }

    return 0;
}